<?php

namespace App\Events;

use \App\Http\Controllers\Controller;
use \GatewayWorker\Lib\Gateway;
use \GatewayWorker\Lib\Db;

// 执行命令
// 用于硬件指令 + 即时消息
class Command
{
    
    // php artisan gwk action
    // php artisan gwk start
    // php artisan gwk restart
    // php artisan gwk stop
    
    public $clientId;  //客户端ID
    public $cmd;       //命令
    
    public function __construct()
    {
    }
    
    // 执行命令
    public function init($clientId, $cmd = null)
    {
        $this->clientId = $clientId;
        $this->cmd      = $cmd;
        
        // 如果有token 解析token
        if (empty($cmd['token'])) {
            
            // 判断token是否与uid一直
        }
        
        // 判断session
        
    }
    
    // 判断用户session
    public function checkUser($uid)
    {
        $my_id = session('my_id');
        if ($my_id != $uid) {
            return false;
        }
        
        return true;
    }
    
    // 抛出异常
    public function throwIf($condition, $message, $code = 400)
    {
        if ($condition) {
            throw new \Exception($message, $code);
        }
    }
    
    // 获取命令信息
    public function getCommandData()
    {
        return $this->cmd;
    }
    
    // 验证参数 不能是一些数据库操作的关键字
    private function checkParam($str)
    {
        $check = preg_match('/select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/i', $str);
        
        return $check == 0;
    }
    
    //获取可选参数，如果不存在，返回默认$default
    public function getParam($name, $default = '', $fun = '')
    {
        if (!isset($this->cmd[$name])) {
            return $default;
        }
        if (!$this->checkParam($this->cmd[$name])) {
            return $default;
        }
        
        $v = $this->cmd[$name];
        if (!empty($fun) && function_exists($fun)) {
            $v = $fun($v);
        }
        
        return $v;
    }
    
    
    //获取命令名
    public function getCmd()
    {
        $return = $this->getParam('cmd');
        
        return $return;
    }
    
    // 输出数据 在命令行显示（向客户端发送的数据） 用于调试
    // $target: 发送数据类型
    public function outputSend($target, $data)
    {
        $cline = chr(10);
        $str   = "   返回消息：client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:{$this->clientId} target: $target message:$data".$cline.$cline;
        $show  = $this->getColoredString($str, 'green');
        echo $show;
    }
    
    //发送数据到当前客户端
    public function sendToCurrentClient($data)
    {
        $data = $this->roles($data);
        $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        Gateway::sendToCurrentClient($data);
        $this->outputSend("sendToClient", $data);
    }
    
    //发送到客户端
    public function sendToClient($clientId, $data)
    {
        $data = $this->roles($data);
        $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        Gateway::sendToClient($clientId, $data);
        $this->outputSend("sendToClient", "clientid:".$clientId.":".$data);
    }
    
    //关闭客户端
    public function closeClient($clientId)
    {
        Gateway::closeClient($clientId);
    }
    
    // 验证数据
    // 有可能各个客户端收到的数据不是一样的 比如：直播间里面的主播，观众收到的消息不一样
    public function roles($data)
    {
        return $data;
    }
    
    ## 替换数组中的字符串
    // 有可能各个客户端收到的数据不是一样的 比如：直播间里面的主播，观众收到的消息不一样
    public function array_replace_string($array, $string, $replace)
    {
        if (is_array($array)) {
            foreach ($array as $key => &$val) {
                $array[$key] = self::array_replace_string($val, $string, $replace);
            }
        } else {
            if (strpos($array, $string) !== false) {
                $array = str_replace($string, $replace, $array);
                //$array   = str_replace("观众", 'guanzhong',$array);
            }
        }
        
        return $array;
    }
    
    
    //发送数据到群
    public function sendToGroup($groupId, $data)
    {
        $data = $this->roles($data);
        $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        Gateway::sendToGroup($groupId, $data);
        //$this->outputSend("sendToGroup", "groupId:".$groupId.":".$data);
        $this->outputSend("sendToGroup", $data);
    }
    
    //发送到所有连接客户端
    public function sendToAll($data)
    {
        $data = $this->roles($data);
        $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        Gateway::sendToAll($data);
        $this->outputSend("sendToAll", $data);
    }
    
    //将客户端加入群
    public function joinGroup($clientId, $groupId)
    {
        Gateway::joinGroup($clientId, $groupId);
    }
    
    //客户端离开群
    public function leaveGroup($clientId, $groupId)
    {
        Gateway::leaveGroup($clientId, $groupId);
    }
    
    //获取客指定组中的客户端session列表
    public function getClientSessionsByGroup($groupId)
    {
        return Gateway::getClientSessionsByGroup($groupId);
    }
    
    //取得指定组的连接客户端数量
    public function getClientCountByGroup($groupId)
    {
        return Gateway::getClientCountByGroup($groupId);
    }
    
    //取得群组中_SESSION[$filed]=$value的值
    public function getGroupClientSession($groupId, $field, $value)
    {
        $sessions = $this->getClientSessionsByGroup($groupId);
        foreach ($sessions as $v) {
            if (isset($v[$field]) && $v[$field] == $value) {
                return $v;
            }
        }
        
        return false;
    }
    
    // 向指定用法发送消息
    public function sendToUid($uid, $data)
    {
        $data = $this->roles($data);
        $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $this->outputSend("sendToUid", $data);
        
        return Gateway::sendToUid($uid, $data);
    }
    
    // 客户端绑定用户
    public function binUid($clientId, $uid)
    {
        return Gateway::bindUid($clientId, $uid);
    }
    
    // 客户端解除绑定用户
    public function unbindUid($clientId, $uid)
    {
        return Gateway::unbindUid($clientId, $uid);
    }
    
    // 获取与 uid 绑定的 client_id 列表
    // 如果为空 则没有绑定
    public function getClientIdsByUid($uid)
    {
        return Gateway::getClientIdByUid($uid);
    }
    
    //取得指定群组中指定uid的客户端SESSION
    public function getGroupClientSessionByUid($groupId, $uid)
    {
        return $this->getGroupClientSession($groupId, 'uid', $uid);
    }
    
    // 组合成功的json
    public function success($data = [])
    {
        $arr = array(
            'cmd'  => $this->cmd['cmd'],
            'code' => 200,
        );
        
        if ($data) {
            $data = is_string($data) ? ['message' => $data] : $data;
            $arr  = array_merge($arr, $data);
        }
        
        return $arr;
    }
    
    // 组合失败的数组
    public function error($data = [])
    {
        $arr = array(
            'cmd'  => $this->cmd['cmd'],
            'code' => 400,
        );
        
        if ($data) {
            $data = is_string($data) ? ['message' => $data] : $data;
            $arr  = array_merge($arr, $data);
        }
        
        return $arr;
    }
    
    //返回错误消息给当前客户端
    public function errorJsonToCurrentClient($message, $code, $sql = '')
    {
        $data = array(
            //'cmd'     => 'Error',
            'cmd'     => $this->cmd['cmd'],
            'code'    => $code,
            'message' => $message,
        );
        
        // 返回 PHP语法错误信息 用于调试
        $errors = error_get_last();
        if ($errors && in_array($errors['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR])) {
            $data['yufa'] = "{$errors['message']} in {$errors['file']} on line {$errors['line']}";
        }
        
        // 返回sql语句 用于调试
        // thinkphp语法
        if ($sql) {
            $data['sql'] = Db::instance('db1')->lastSQL();
        }
        
        $this->sendToCurrentClient($data);
    }
    
    //返回正确消息给当前客户端
    public function successJsonToCurrentClient($message = '', $data = [])
    {
        $arr = array(
            'cmd'     => $this->cmd['cmd'],
            'code'    => 200,
            'message' => $message,
        );
        
        if ($data) {
            $arr = array_merge($arr, $data);
        }
        
        $this->sendToCurrentClient($arr);
    }
    
    //取得直播房间的组ID
    public function liveRoomId($roomId)
    {
        return 'live:'.$roomId;
    }
    
    
    //向直播间推送系统消息
    public function SendSysMessageToRoom($roomid, $message)
    {
        $data['cmd']     = 'app_room_chat';
        $data['channel'] = 'system';
        $data['roomid']  = $roomid;
        $data['message'] = $message;
        if (empty($roomid)) {
            $this->sendToAll($data);
            
            return;
        }
        $roomida = $this->liveRoomId($roomid);
        $this->sendToGroup($roomida, $data);
    }
    
    //向直播间推送系统消息
    public function SendSysMessageToCurrentClient($roomid, $message)
    {
        $data['cmd']     = 'app_room_chat';
        $data['channel'] = 'system';
        $data['roomid']  = $roomid;
        $data['message'] = $message;
        if (empty($roomid)) {
            $this->sendToAll($data);
            
            return;
        }
        
        $this->sendToCurrentClient($data);
    }
    
    // 模拟请求 聊天数据
    public function curlChat($controller, $other = [], $where = [], $data = [])
    {
        $dealController = new Controller();
        
        return $dealController->curlDatas($controller, $other, $where, $data, 'Chat');
    }
    
    
    // 返回带颜色的字符串  用于命令行展示
    public function getColoredString($string, $fore_color = null, $back_color = null)
    {
        
        $forecolors = [
            'black'        => '0;30',
            'dark_gray'    => '1;30',
            'blue'         => '0;34',
            'light_blue'   => '1;34',
            'green'        => '0;32',
            'light_green'  => '1;32',
            'cyan'         => '0;36',
            'light_cyan'   => '1;36',
            'red'          => '0;31',
            'light_red'    => '1;31',
            'purple'       => '0;35',
            'light_purple' => '1;35',
            'brown'        => '0;33',
            'yellow'       => '1;33',
            'light_gray'   => '0;37',
            'white'        => '1;37',
        ];
        
        $linuxforecolors = [
            'black'      => '0;30',
            'red'        => '0;31',
            'green'      => '0;32',
            'brown'      => '0;33',
            'blue'       => '0;34',
            'purple'     => '0;35',
            'cyan'       => '0;36',
            'light_gray' => '0;37',
        ];
        
        $back_colors = [
            'black'      => '40',
            'red'        => '41',
            'green'      => '42',
            'yellow'     => '43',
            'blue'       => '44',
            'magenta'    => '45',
            'cyan'       => '46',
            'light_gray' => '47',
        ];
        
        /**
         * linux 颜色
         * echo -e “\033[44;37;5m 输出的字符串\033[0m”
         * \033[44;37;5m ME
         * \033[背景色数字;前景色前景;动作数据m ME
         * // 0、重新设置属性到缺省设置  1、设置粗体  2、设置一半亮度(模拟彩色显示器的颜色) 4、设置下划线(模拟彩色显示器的颜色) 5、设置闪烁
         */
        
        // 前景
        $show = "";
        $show .= "\033[".$forecolors[$fore_color]."m";
        
        // 背景
        $back = isset($back_colors[$back_color]) ? $back_colors[$back_color] : 49;
        $show .= "\033[".$back."m";
        
        // 添加字符串 和 结束颜色
        $show .= $string."\033[;0m";
        
        return $show;
    }
    
}